<?php

namespace model;

/**
 * Description of Model
 *
 * @author Damian
 */
class Model extends ModelBase {

    /**
     * <p>bufor na dane</p>
     * @var \library\cache\Memcached  
     */
    protected $cache;

    /**
     *
     * @var \library\Session\Server
     */
    protected $session;

    public function __construct($options = array()) {
        parent::__construct($options);
        $this->cache = \library\Registry::get("cache");
        $this->cache->connect();
        $this->session = \library\Registry::get("session");
    }

    public function getColumns() {//zapisanie kolumn danej tabeli do sesji bo się pow
  //      $this->session->erase($this->getTable()."_columns");
        if ($this->session->get($this->getTable() . "_columns")) {
            $columns = $this->session->get($this->getTable() . "_columns");
            $this->columns = $columns;
            $this->primary = $this->session->get($this->getTable() . "_primaryColumn");
            $this->session->get($this->getTable() . "_relations", $this->relations);
            $this->relations = $this->session->get($this->getTable() . "_relations");
           // var_dump($this->columns);
            return $this->columns;
        } else {
            $columns = parent::getColumns();
            $this->session->set($this->getTable() . "_columns", $columns);
            $this->session->set($this->getTable() . "_relations", $this->relations);
            $this->session->set($this->getTable() . "_primaryColumn", $this->primary);
            return $columns;
        }
    }

    /**
     * @read
     */
    protected $validators = array(
        "required" => array(
            "handler" => "_validateRequired",
            "message" => "Pole {0} jest wymagane"
        ),
        "alpha" => array(
            "handler" => "_validateAlpha",
            "message" => "Pole {0} może zawierać tylko litery, kropkę, przecinek, średnik, dwukropek, myślinik, podkreśnik"
        ),
        "onlyletters" => array(
            "handler" => "_validateOnlyLetters",
            "message" => "Pole {0} może zawierać tylko litery i spacje"
        ),
        "numeric" => array(
            "handler" => "_validateNumeric",
            "message" => "Pole {0} może zawierać tylko liczby"
        ),
        "email" => array(
            "handler" => "_validateEmail",
            "message" => "Wprowadź poprany adres mailowy"
        ),
        "alphanumeric" => array(
            "handler" => "_validateAlphaNumeric",
            "message" => "Pole {0} może zawierać tylko litery, kropkę, przecinek, średnik, dwukropek, białe znaki i liczby"
        ),
        "max" => array(
            "handler" => "_validateMax",
            "message" => "Pole {0} musi zawierać mniej niż {2} znak"
        ),
        "min" => array(
            "handler" => "_validateMin",
            "message" => "Pole {0} musi zawierać wiecej niż {2} znak"
        ),
        "minValue" => array(
            "handler" => "_validateMaxValue",
            "message" => "Pole {0} musi być równe co najmniej {2}"
    ));

    /**
     * @read
     */
    protected $errors;
    public $validatePassed = true;
    protected $allowedValues = array();
    protected function _validateRequired($value) {
        return !empty($value);
    }

    protected function _validateAlpha($value) {
        return \library\StringMethods::match(strip_tags($value), "#^'?([ąćęńśóźżła-zA-Z\-_:;,\.\s]+)'?$#");
    }

    protected function _validateOnlyLetters($value) {
        return \library\StringMethods::match(strip_tags($value), "#^'?([a-zA-Z\s]+)'?$#");
    }

    protected function _validateEmail($value) {
        return \library\StringMethods::match($value, "#^'?[a-zA-Z0-9\.\-_]+\@[a-zA-Z0-9\.\-_]+\.[a-z]{2,4}'?$#");
    }

    protected function _validateNumeric($value) {
        return is_numeric($value) || $value === "0" || $value === 0;
    }

    protected function _validateAlphaNumeric($value) {
       return \library\StringMethods::match(strip_tags($value), "#^([ąćęńśóźżła-zA-Z0-9\-_:;,\.\s]+)$#");
    }

    protected function _validateMax($value, $number) {
        return strlen($value) <= (int) $number;
    }

    protected function _validateMin($value, $number) {
        return strlen($value) >= (int) $number;
    }

    protected function _validateMinValue($value, $number) {
        if (!$this->_validateNumeric($value)) {
            return $this->_validateNumeric($value);
        }
        return ($value < $number);
    }

    protected function _validateMaxValue($value, $number) {
        if (!$this->_validateNumeric($value)) {
            return $this->_validateNumeric($value);
        }
        return ($value > $number);
    }

    public function validate() {
      //  $temp = new \SplFileObject(time() . ".txt", "w");
        $this->errors = array();
        $columns = $this->getColumns();
        $error = false;
        foreach ($columns as $column) {
            if ($column->validate) {
                $pattern = "#[a-z]+\(([a-zA-Z0-9, ]+)\)#";
                $raw = $column->raw;
                $name = $column->name;
                if (!$column->isObject) {
                 //   $temp->fwrite($name . "=>" . $this->$name);
                }

                $validators = $column->validate;
                $label = $column->label;
                $defined = $this->getValidators();
                foreach ($validators as $validator) {
                    $function = $validator;
                    $arguments = [$this->$raw];
                    $match = \library\StringMethods::match($validator, $pattern);
                    if (count($match) > 0) {
                        $matches = \library\StringMethods::split($match[0], $pattern);
                        $arguments = array_merge($arguments, $matches);
                        $offset = \library\StringMethods::indexOf($validator, "(");
                        $function = substr($validator, 0, $offset);
                    }
                    if (!isset($defined[$function])) {
                        throw new exceptions\ValidatorException("Walidator {$function} nie jest zdefiniowany");
                    }
                    $template = $defined[$function];
                    if (!call_user_func_array(array($this, $template["handler"]), $arguments)) {
                        $replacements = array_merge(array(
                            $label ? $label : $raw
                                ), $arguments);
                        $message = $template["message"];
                        if ($template["handler"] == "_validateMin" || $template["handler"] == "_validateMax") {
                            $elem = (int) $arguments[1];
                            if ($elem < 20 && $elem > 10) {
                                $message.="ów";
                            } else {
                                $reszta = $elem % 10;
                                switch ($reszta) {
                                    case 2:
                                    case 3:
                                    case 4: $message.="i";
                                        break;
                                    default :$message.="ów";
                                }
                            }
                        }
                        foreach ($replacements as $i => $replacement) {
                            $message = str_replace("{{$i}}", $replacement, $message);
                        }
                        if (!isset($this->errors[$name])) {
                            $this->errors[$name] = array();
                        }
                        $this->errors[$name][] = $message;
                        $error = true;
                    }
                }
            }
        }
        return !$error;
    }

    public static function getModel() {
        return new static;
    }

    public function getByPrimaryKey($id) {
        $col = $this->getPrimaryColumn();
        $this->getConnector();
        $ida = $this->connector->escape($id);
        try {
            $key = $this->getTable() . "_" . $id;
            @$object = $this->cache->get($key);
            if ($object) {
                return $object;
            } else {
                $result = $this->connector->executeSQL("select * from `{$this->getTable()}` where `{$col->name}`={$ida} limit 1");
                if ($result->rowCount() == 0) {
                    throw new \model\exceptions\WrongIDException("nie istnieje " . get_class($this) . " o id = {$id}");
                }
                $obi = $result->fetch(\PDO::FETCH_ASSOC);
                unset($result);
                $class = get_class($this);
                $res = new $class($obi);
               @$this->cache->set($key, $res, 3600);
                return $res;
            }
        } catch (\model\exceptions\ExceptionSQLQuery $e) {
            if ($e instanceof exceptions\NoDataException) {
                return null;
            }
            throw new exceptions\WrongIDException();
        } finally {
            $this->connector = null;
        }
    }

}
